Micron Document
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
| SparkN0de-git | SparkN0de |
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

Node / ReticulumProjects / MeshChatX.git / files / tests / backend / test_database_evolution.py

Displaying Raw • Download


tests/backend/test_database_evolution.py 30ef8856dc7cfc97b8e8c6de36f7de33bd32cc99 (30ef8856) Text, 5.28 KB

Tff7b72import T7ee787os
Tff7b72import T7ee787shutil
Tff7b72import T7ee787sqlite3
Tff7b72import T7ee787tempfile
Tff7b72import T7ee787unittest
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787database Tff7b72import Te6edf3Database
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787databaseT7ee787.T7ee787provider Tff7b72import Te6edf3DatabaseProvider
Tff7b72from T7ee787meshchatxT7ee787.T7ee787srcT7ee787.T7ee787backendT7ee787.T7ee787databaseT7ee787.T7ee787legacy_migrator Tff7b72import Te6edf3LegacyMigrator


Tff7b72class T56d364TestDatabaseMigrationTb4b4b4(Te6edf3unittestTff7b72.Td2a8ffTestCaseTb4b4b4)Tb4b4b4:
Tff7b72def Td2a8ffsetUpTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3DatabaseProviderTff7b72.Td2a8ff_instance Tff7b72= Tff7b72None
Tff7b72selfTff7b72.Td2a8fftest_dir Tff7b72= Te6edf3tempfileTff7b72.Td2a8ffmkdtempTb4b4b4(Tb4b4b4)
T8b949e# Legacy migrator expects a specific structure: reticulum_config_dir/identities/identity_hash_hex/database.db
Tff7b72selfTff7b72.Td2a8ffidentity_hash Tff7b72= Ta5d6ff"Ta5d6ffdeadbeefTa5d6ff"
Tff7b72selfTff7b72.Td2a8fflegacy_config_dir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8fftest_dirTb4b4b4, Ta5d6ff"Ta5d6fflegacy_configTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8fflegacy_db_subdir Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(
Tff7b72selfTff7b72.Td2a8fflegacy_config_dirTb4b4b4, Ta5d6ff"Ta5d6ffidentitiesTa5d6ff"Tb4b4b4, Tff7b72selfTff7b72.Td2a8ffidentity_hash
Tb4b4b4)
Te6edf3osTff7b72.Td2a8ffmakedirsTb4b4b4(Tff7b72selfTff7b72.Td2a8fflegacy_db_subdirTb4b4b4, Te6edf3exist_okTff7b72=Tff7b72TrueTb4b4b4)
Tff7b72selfTff7b72.Td2a8fflegacy_db_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8fflegacy_db_subdirTb4b4b4, Ta5d6ff"Ta5d6ffdatabase.dbTa5d6ff"Tb4b4b4)

T8b949e# Create legacy database with 1.x/2.x schema
Tff7b72selfTff7b72.Td2a8ffcreate_legacy_dbTb4b4b4(Tff7b72selfTff7b72.Td2a8fflegacy_db_pathTb4b4b4)

T8b949e# Current database
Tff7b72selfTff7b72.Td2a8ffcurrent_db_path Tff7b72= Te6edf3osTff7b72.Td2a8ffpathTff7b72.Td2a8ffjoinTb4b4b4(Tff7b72selfTff7b72.Td2a8fftest_dirTb4b4b4, Ta5d6ff"Ta5d6ffcurrent.dbTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffdb Tff7b72= Te6edf3DatabaseTb4b4b4(Tff7b72selfTff7b72.Td2a8ffcurrent_db_pathTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffinitializeTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8fftearDownTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffclose_allTb4b4b4(Tb4b4b4)
Te6edf3shutilTff7b72.Td2a8ffrmtreeTb4b4b4(Tff7b72selfTff7b72.Td2a8fftest_dirTb4b4b4)

Tff7b72def Td2a8ffcreate_legacy_dbTb4b4b4(Tff7b72selfTb4b4b4, Te6edf3pathTb4b4b4)Tb4b4b4:
Te6edf3conn Tff7b72= Te6edf3sqlite3Tff7b72.Td2a8ffconnectTb4b4b4(Te6edf3pathTb4b4b4)
Te6edf3cursor Tff7b72= Te6edf3connTff7b72.Td2a8ffcursorTb4b4b4(Tb4b4b4)

T8b949e# Based on liamcottle/reticulum-meshchat/database.py
Te6edf3cursorTff7b72.Td2a8ffexecuteTb4b4b4(Ta5d6ff"""
Ta5d6ff CREATE TABLE config (
Ta5d6ff id INTEGER PRIMARY KEY AUTOINCREMENT,
Ta5d6ff key TEXT UNIQUE,
Ta5d6ff value TEXT,
Ta5d6ff created_at DATETIME,
Ta5d6ff updated_at DATETIME
Ta5d6ff )
Ta5d6ff Ta5d6ff"""Tb4b4b4)

Te6edf3cursorTff7b72.Td2a8ffexecuteTb4b4b4(Ta5d6ff"""
Ta5d6ff CREATE TABLE announces (
Ta5d6ff id INTEGER PRIMARY KEY AUTOINCREMENT,
Ta5d6ff destination_hash TEXT UNIQUE,
Ta5d6ff aspect TEXT,
Ta5d6ff identity_hash TEXT,
Ta5d6ff identity_public_key TEXT,
Ta5d6ff app_data TEXT,
Ta5d6ff rssi INTEGER,
Ta5d6ff snr REAL,
Ta5d6ff quality REAL,
Ta5d6ff created_at DATETIME,
Ta5d6ff updated_at DATETIME
Ta5d6ff )
Ta5d6ff Ta5d6ff"""Tb4b4b4)

Te6edf3cursorTff7b72.Td2a8ffexecuteTb4b4b4(Ta5d6ff"""
Ta5d6ff CREATE TABLE lxmf_messages (
Ta5d6ff id INTEGER PRIMARY KEY AUTOINCREMENT,
Ta5d6ff hash TEXT UNIQUE,
Ta5d6ff source_hash TEXT,
Ta5d6ff destination_hash TEXT,
Ta5d6ff state TEXT,
Ta5d6ff progress REAL,
Ta5d6ff is_incoming INTEGER,
Ta5d6ff method TEXT,
Ta5d6ff delivery_attempts INTEGER,
Ta5d6ff next_delivery_attempt_at REAL,
Ta5d6ff title TEXT,
Ta5d6ff content TEXT,
Ta5d6ff fields TEXT,
Ta5d6ff timestamp REAL,
Ta5d6ff rssi INTEGER,
Ta5d6ff snr REAL,
Ta5d6ff quality REAL,
Ta5d6ff created_at DATETIME,
Ta5d6ff updated_at DATETIME
Ta5d6ff )
Ta5d6ff Ta5d6ff"""Tb4b4b4)

T8b949e# Insert some legacy data
Te6edf3cursorTff7b72.Td2a8ffexecuteTb4b4b4(
Ta5d6ff"Ta5d6ffINSERT INTO config (key, value) VALUES (?, ?)Ta5d6ff"Tb4b4b4,
Tb4b4b4(Ta5d6ff"Ta5d6fflegacy_keyTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6fflegacy_valueTa5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3cursorTff7b72.Td2a8ffexecuteTb4b4b4(
Ta5d6ff"Ta5d6ffINSERT INTO announces (destination_hash, aspect, identity_hash) VALUES (?, ?, ?)Ta5d6ff"Tb4b4b4,
Tb4b4b4(Ta5d6ff"Ta5d6ffdest1Ta5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6fflxmf.deliveryTa5d6ff"Tb4b4b4, Ta5d6ff"Ta5d6ffid1Ta5d6ff"Tb4b4b4)Tb4b4b4,
Tb4b4b4)
Te6edf3cursorTff7b72.Td2a8ffexecuteTb4b4b4(
Ta5d6ff"Ta5d6ffINSERT INTO lxmf_messages (hash, source_hash, destination_hash, title, content, fields, is_incoming, state, progress, timestamp) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?)Ta5d6ff"Tb4b4b4,
Tb4b4b4(
Ta5d6ff"Ta5d6ffmsg1Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffsrc1Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffdest1Ta5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffOld TitleTa5d6ff"Tb4b4b4,
Ta5d6ff"Ta5d6ffOld ContentTa5d6ff"Tb4b4b4,
Ta5d6ff"Tffd700{}Ta5d6ff"Tb4b4b4,
T79c0ff1Tb4b4b4,
Ta5d6ff"Ta5d6ffdeliveredTa5d6ff"Tb4b4b4,
T79c0ff1.0Tb4b4b4,
T79c0ff123456789.0Tb4b4b4,
Tb4b4b4)Tb4b4b4,
Tb4b4b4)

Te6edf3connTff7b72.Td2a8ffcommitTb4b4b4(Tb4b4b4)
Te6edf3connTff7b72.Td2a8ffcloseTb4b4b4(Tb4b4b4)

Tff7b72def Td2a8fftest_migration_evolutionTb4b4b4(Tff7b72selfTb4b4b4)Tb4b4b4:
Te6edf3migrator Tff7b72= Te6edf3LegacyMigratorTb4b4b4(
Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffproviderTb4b4b4, Tff7b72selfTff7b72.Td2a8fflegacy_config_dirTb4b4b4, Tff7b72selfTff7b72.Td2a8ffidentity_hash
Tb4b4b4)

T8b949e# Check if should migrate
Tff7b72selfTff7b72.Td2a8ffassertTrueTb4b4b4(
Te6edf3migratorTff7b72.Td2a8ffshould_migrateTb4b4b4(Tb4b4b4)Tb4b4b4, Ta5d6ff"Ta5d6ffShould detect legacy database for migrationTa5d6ff"
Tb4b4b4)

T8b949e# Perform migration
Te6edf3success Tff7b72= Te6edf3migratorTff7b72.Td2a8ffmigrateTb4b4b4(Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertTrueTb4b4b4(Te6edf3successTb4b4b4, Ta5d6ff"Ta5d6ffMigration should complete successfullyTa5d6ff"Tb4b4b4)

T8b949e# Verify data in current database
Te6edf3config_rows Tff7b72= Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchallTb4b4b4(Ta5d6ff"Ta5d6ffSELECT * FROM configTa5d6ff"Tb4b4b4)
Tffa657printTb4b4b4(Ta5d6fffTa5d6ff"Ta5d6ffConfig rows: Tffd700{Te6edf3config_rowsTffd700}Ta5d6ff"Tb4b4b4)

Te6edf3config_val Tff7b72= Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchoneTb4b4b4(
Ta5d6ff"Ta5d6ffSELECT value FROM config WHERE key = ?Ta5d6ff"Tb4b4b4, Tb4b4b4(Ta5d6ff"Ta5d6fflegacy_keyTa5d6ff"Tb4b4b4,Tb4b4b4)
Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertIsNotNoneTb4b4b4(Te6edf3config_valTb4b4b4, Ta5d6ff"Ta5d6fflegacy_key should have been migratedTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3config_valTb4b4b4[Ta5d6ff"Ta5d6ffvalueTa5d6ff"Tb4b4b4]Tb4b4b4, Ta5d6ff"Ta5d6fflegacy_valueTa5d6ff"Tb4b4b4)

Te6edf3ann_count Tff7b72= Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchoneTb4b4b4(
Ta5d6ff"Ta5d6ffSELECT COUNT(*) as count FROM announcesTa5d6ff"
Tb4b4b4)Tb4b4b4[Ta5d6ff"Ta5d6ffcountTa5d6ff"Tb4b4b4]
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3ann_countTb4b4b4, T79c0ff1Tb4b4b4)

Te6edf3msg Tff7b72= Tff7b72selfTff7b72.Td2a8ffdbTff7b72.Td2a8ffproviderTff7b72.Td2a8fffetchoneTb4b4b4(
Ta5d6ff"Ta5d6ffSELECT * FROM lxmf_messages WHERE hash = ?Ta5d6ff"Tb4b4b4, Tb4b4b4(Ta5d6ff"Ta5d6ffmsg1Ta5d6ff"Tb4b4b4,Tb4b4b4)
Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertIsNotNoneTb4b4b4(Te6edf3msgTb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3msgTb4b4b4[Ta5d6ff"Ta5d6fftitleTa5d6ff"Tb4b4b4]Tb4b4b4, Ta5d6ff"Ta5d6ffOld TitleTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3msgTb4b4b4[Ta5d6ff"Ta5d6ffcontentTa5d6ff"Tb4b4b4]Tb4b4b4, Ta5d6ff"Ta5d6ffOld ContentTa5d6ff"Tb4b4b4)
Tff7b72selfTff7b72.Td2a8ffassertEqualTb4b4b4(Te6edf3msgTb4b4b4[Ta5d6ff"Ta5d6ffsource_hashTa5d6ff"Tb4b4b4]Tb4b4b4, Ta5d6ff"Ta5d6ffsrc1Ta5d6ff"Tb4b4b4)


Tff7b72if Tff7b72__name__ Tff7b72== Ta5d6ff"Ta5d6ff__main__Ta5d6ff"Tb4b4b4:
Te6edf3unittestTff7b72.Td2a8ffmainTb4b4b4(Tb4b4b4)


──────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────────